home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 46
/
Aminet 46 (2001)(GTI - Schatztruhe)[!][Dec 2001].iso
/
Aminet
/
text
/
edit
/
edt10src.lha
/
txt
/
Threads.mod
< prev
next >
Wrap
Text File
|
1995-03-19
|
5KB
|
209 lines
(*
.name Threads
.task multithreading
.release 1.0
.language Oberon-2
.translator Amiga Oberon 3.11
.system AmigaOS 2.04/2.1/3.0
.author J. Barheine
.address Hochgrevestr. 3
.copyright (c) 1995 by J. Barheine
*)
(* .info: 06/09/93, 15:35:27, version 00 *)
MODULE Threads;
IMPORT
SYS:= SYSTEM,
Dos,
Exec,
K:= Kernel,
OberonLib;
TYPE
Waiting = UNTRACED POINTER TO WaitingDesc;
Thread* = UNTRACED POINTER TO ThreadDesc;
ThreadProc* = PROCEDURE (data: K.ANY): K.ANY;
ThreadDesc* = RECORD (K.ANYDesc)
next: Thread; (* link *)
dosProcess: Dos.ProcessPtr; (* AmigaOS-Thread *)
done: BOOLEAN; (* terminated? *)
data: K.ANY; (* passed data *)
result: K.ANY; (* result of this thread *)
taskTrapData: OberonLib.TaskTrapData;
proc: ThreadProc; (* The main thread procedure *)
waiting: Waiting; (* thread waiting for our termination *)
END;
WaitingDesc = RECORD (K.ANYDesc)
next: Waiting; (* link *)
task: Exec.TaskPtr; (* waiting task *)
END;
VAR
threadList: Thread;
startThreadProc: Thread;
sema: Exec.SignalSemaphore;
wakeUpSig: INTEGER;
defStackSize: LONGINT;
dataIndex: INTEGER; (* taskTrapData.user[] - index *)
PROCEDURE ChildHaltProc;
VAR
p, q: Thread;
CONST
rts = 4E75H;
BEGIN
p:= SYS.VAL(Thread, OberonLib.execBase.thisTask.trapData.user[dataIndex]);
Exec.ObtainSemaphore(sema);
Exec.Forbid;
p.done:= TRUE;
WHILE p.waiting # NIL DO
Exec.Signal(p.waiting.task, LONGSET{wakeUpSig});
p.waiting:= p.waiting.next;
END;
IF p = threadList THEN
threadList:= p.next
ELSE
q:= threadList;
WHILE q.next # p DO q:= q.next END;
q.next:= p.next;
END;
Exec.ReleaseSemaphore(sema);
SYS.SETREG(15, OberonLib.execBase.thisTask.trapData.oldSP);
SYS.INLINE(rts);
END ChildHaltProc;
PROCEDURE Call(p: Thread);
BEGIN
p.result:= p.proc(p.data);
ChildHaltProc;
END Call;
(* $StackChk- *)
PROCEDURE StartProc;
BEGIN
startThreadProc:= SYS.VAL(Thread, OberonLib.execBase.thisTask.trapData.user[dataIndex]);
Call(startThreadProc);
END StartProc;
PROCEDURE StartThread; (* sets A5 and trapData.oldSP *)
BEGIN
OberonLib.SetA5;
(* $IF SmallData *)
OberonLib.execBase.thisTask.trapData.oldSP:= SYS.REG(15);
(* $ELSE *)
OberonLib.execBase.thisTask.trapData.oldSP:= SYS.VAL(LONGINT, SYS.REG(15))-4;
(* $END *)
StartProc;
END StartThread;
(* $StackChk= *)
(* run proc in a seperate thread *)
PROCEDURE RunInThread* (proc: ThreadProc; data: K.ANY; priority: SHORTINT): Thread;
VAR
p: Thread;
msg: Dos.ProcessId;
BEGIN
NEW(p);
p.taskTrapData:= OberonLib.execBase.thisTask.trapData^;
p.taskTrapData.haltProc:= ChildHaltProc;
p.taskTrapData.user[dataIndex]:= SYS.VAL(SYS.ADDRESS, p);
p.data:= data;
p.proc:= proc;
p.done:= FALSE;
Exec.ObtainSemaphore(sema);
Exec.Forbid;
p.dosProcess:= Dos.CreateNewProcTags(Dos.npEntry, SYS.VAL(SYS.ADDRESS, StartThread),
Dos.npStackSize, defStackSize,
Dos.npPriority , priority);
IF p.dosProcess # NIL THEN
p.dosProcess.task.trapData:= SYS.ADR(p.taskTrapData);
p.dosProcess.task.trapCode:= Exec.exec.thisTask.trapCode;
p.next:= threadList;
threadList:= p;
ELSE
p:= NIL;
END;
Exec.Permit;
Exec.ReleaseSemaphore(sema);
RETURN p;
END RunInThread;
(* wait for p to terminate *)
PROCEDURE (p: Thread) Wait* (): K.ANY;
VAR
wait: Waiting;
BEGIN
Exec.ObtainSemaphore(sema);
IF ~p.done THEN
NEW(wait);
wait.task:= Exec.exec.thisTask;
wait.next:= p.waiting;
p.waiting:= wait;
Exec.ReleaseSemaphore(sema);
REPEAT UNTIL p.done OR (wakeUpSig IN Exec.Wait(LONGSET{wakeUpSig}));
ELSE
Exec.ReleaseSemaphore(sema);
END;
RETURN p.result;
END Wait;
(* check if p is still running *)
PROCEDURE (p: Thread) IsRunning* (): BOOLEAN;
BEGIN
RETURN ~p.done
END IsRunning;
(* wait for all threads to terminate *)
PROCEDURE WaitForAllThreads* ;
VAR
p: Thread;
BEGIN
LOOP
Exec.ObtainSemaphore(sema);
p:= threadList;
Exec.ReleaseSemaphore(sema);
IF p = NIL THEN EXIT END;
IF p.Wait()=NIL THEN END;
END;
END WaitForAllThreads;
BEGIN
Exec.InitSemaphore(sema);
threadList:= NIL;
defStackSize:= OberonLib.OldSP.stackSize;
wakeUpSig:= Exec.AllocSignal(-1);
dataIndex:= OberonLib.AllocUser();
IF (wakeUpSig < 0) OR (dataIndex < 0) THEN HALT(20) END;
CLOSE
WaitForAllThreads;
IF wakeUpSig >= 0 THEN Exec.FreeSignal(wakeUpSig) END;
IF dataIndex >= 0 THEN OberonLib.FreeUser(dataIndex) END;
END Threads.